
if (not commonlib.USE_LUA_EXPAT) then return {} end
 
local function EncodeStr(s)
	local s = tostring(s);
	if(not s)then return end
	s = string.gsub(s, "&", "&amp;");
	s = string.gsub(s, "\'", "&apos;");
	s = string.gsub(s, "<", "&lt;");
	s = string.gsub(s, ">", "&gt;");
	s = string.gsub(s, "\"", "&quot;");
	return s;
end

local function EncodeHTMLInnerText(s)
	local s = tostring(s);
	if(not s)then return end
	s = string.gsub(s, "&", "&amp;");
	-- s = string.gsub(s, "\'", "&apos;");
	s = string.gsub(s, "<", "&lt;");
	s = string.gsub(s, ">", "&gt;");
	-- s = string.gsub(s, "\"", "&quot;");
	return s;
end

local function EncodeHTMLInnerTextWithSpace(s)
	local s = tostring(s);
	if(not s) then return end
	s = string.gsub(s, "&", "&amp;");
	s = string.gsub(s, "<", "&lt;");
	s = string.gsub(s, ">", "&gt;");
	s = string.gsub(s, "  ", " &#32;");
	s = string.gsub(s, "\r", "&#13;");
	s = string.gsub(s, "\n", "&#10;");
	return s;
end

local function ToXmlString(input, bBeautify, sortByKey, tagName, attrName)
    tagName = tagName or "tag";
    attrName = attrName or "attr";

	if(not input) then return end
	
    local output = {};
	local indent = 0;
	
    local function OutputNode(inTable)
		if(not inTable) then return end
        if(type(inTable) == "string") then 
            if (bBeautify) then
                table.insert(output, "\n" .. string.rep("\t", indent) .. EncodeHTMLInnerTextWithSpace(inTable));
            else
                table.insert(output, EncodeHTMLInnerTextWithSpace(inTable));
            end
            return;
        end
		if(type(inTable) == "table") then 	
            local tag = inTable[tagName];
            if (not tag) then return end 
            if(tag == "![CDATA[") then
                table.insert(output, "<".. tag)
                for i, childNode in ipairs(inTable) do
                    if(type(childNode)=="string") then
                        table.insert(output, childNode)
                    end
                end
                table.insert(output, "]]>");
                return 
            end

            -- normal tag
            if (bBeautify) then 
                table.insert(output, "\n" .. string.rep("\t", indent) .. "<" .. tag);
            else 
                table.insert(output, "<" .. tag);
            end
            local attr = inTable[attrName];
            if(attr) then
                local name, value
                if sortByKey then
                    local sortTable = {};
                    for name, value in pairs(attr) do
                        table.insert(sortTable, {key = name, value = value});
                    end
                    table.sort(sortTable, function(a, b) return a.key < b.key; end);	
                    for _, att in ipairs(sortTable) do
                        table.insert(output, string.format(" %s=\"%s\"", att.key, EncodeStr(att.value)))
                    end
                else
                    for name, value in pairs(attr) do
                        table.insert(output, string.format(" %s=\"%s\"", name, EncodeStr(value)))
                    end
                end
            end
            table.insert(output, ">");

            -- children
            indent = indent + 1;
            for i, childNode in ipairs(inTable) do
                OutputNode(childNode);
            end
            indent = indent - 1;

            -- end element
            if(bBeautify) then
                table.insert(output, "\n"..string.rep("\t", indent) .. "</" .. tag .. ">");
            else
                table.insert(output, "</" .. tag .. ">");
            end
		end
	end
	OutputNode(input)
	return table.concat(output);
end

local lom = require("lxp.lom");

local function string_trim(str, ch)
	ch = ch or "%s";
    str = string.gsub(str, "^" .. ch .. "*", "");
    str = string.gsub(str, ch .. "*$", "");
    return str;
end

local function FromXmlString(xmlStr, tagName, attrName)
    tagName = tagName or "tag";
    attrName = attrName or "attr";

    local function XmlToLua(xmlNode)
        if (type(xmlNode) == "string") then
            return string_trim(xmlNode);
        end
        if (type(xmlNode) ~= "table") then return nil end
        local luaObj = {[tagName] = xmlNode.tag, [attrName] = {}};
        local luaObjAttr = luaObj[attrName];
        for _, key in ipairs(xmlNode.attr) do
            luaObjAttr[key] = xmlNode.attr[key];
        end
        for _, subXmlNode in ipairs(xmlNode) do
            local subLuaObj = XmlToLua(subXmlNode);
            if (subLuaObj and subLuaObj ~= "") then
                table.insert(luaObj, subLuaObj);
            end
        end
        return luaObj;
    end
    return XmlToLua(lom.parse(xmlStr));
end

return {
    ToXmlString = ToXmlString,
    FromXmlString = FromXmlString,
}